/* dwifiTCP.cpp
   For use with the Dexter Industries dWIFI
   The dWiFi can be found here:  http://dexterindustries.com/wifi */

#include "string.h"
#include "ctype.h"
#include "SoftwareSerial.h"
#include "pins_arduino.h"
#include "math.h"
#include "Arduino.h"
#include "dwifiTCP.h"

#define SoftRxPin 13
#define SoftTxPin 12
#define RTS 10
#define CTS 11
#define CTS_PIN_SHIFT 3    // UNO Board, pins set to first configuration. This will depend on your board; your setup.

/*  Arduino Baud Rates=> {300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 31250, 38400, 57600, 115200};
    WiFi Baud Rates   => {9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600};
    Common Baud Rates => {9600, 19200, 38400, 57600, 115200}; */

/* Initialize Software Serial connection. */ 
SoftwareSerial wifiSerial=SoftwareSerial(SoftRxPin, SoftTxPin);

/* Function to start Software Serial connection. */
void dwifiTCP::init()
{ 
  /* Example call to function : init(); */  
  memset(buffer, ' ', sizeof(buffer));
  wifiSerial.begin(9600);        // Wifi Baud Rates
  pinMode(CTS, OUTPUT);
  delay(100);
  commandStr="";      // String used for passing commands to WiFi Sheild
  bytewifi=-1;           // Byte Received, read as integer.
//  ssid="JASMEET";     // SSID of Network
//  ind="1";            // Index (1 to 4) used for WEP Key only
//  key="JASS1MEET";    // WEP Key of 10 or 26 hexadecimal characters OR WPA Passphrase of 8 to 63 ASCII characters
  long baudrates[5]={9600, 19200, 38400, 57600, 115200};
}

/* Function to read string data from Serial Monitor Box. String ends with linefeed character (ASCII value=10). */
String dwifiTCP::getstr()
{
  /* Example Call to function: String STR= getstr(); */
  output="";
  char c;
  delay(8000);                       // Delay of 8 seconds to ensure you can type data in the Serial Monitor.
  while (Serial.available()==0){;}   // If nothing available in serial buffer, wait and do nothing.
  while (Serial.available()) {       // Read data from serial buffer.
    delay(5);  
    if (Serial.available() >0) {
      c = Serial.read();      // Read character from serial buffer and
      if((int(c)!=10) && (int(c)!=13)){
        output += c;}                    // concatenate it to existing string.
      }
    }
  Serial.println(output);
  return output;
}

/* Set CTS pin low. Clear to Send. */
void dwifiTCP::CTS_start()
{
  PORTB = PORTB &~(1 << CTS_PIN_SHIFT);
}

/* Set CTS pin high.  Not Clear to Send. */
void dwifiTCP:: CTS_stop()
{
  PORTB = PORTB | (1 << CTS_PIN_SHIFT);
}

/* Check to see RTS. */
boolean dwifiTCP::RTS_check()
{
  if(!digitalRead(RTS)){return true;}
  else{ return false; } 
}

/* Function used to write variable commands (stored as a String) to WiFi. Returns the number of bytes sent. */
void dwifiTCP::writeStr(String str)
{
  /* Example Call to function: int bytesWritten = writeStr(commandStr); 
     Where commandStr is a String object. */
  Serial.print(str);
  CTS_stop();
  char ch;
  for(int i=0; i<str.length(); i++){
    ch=str.charAt(i);
    if((int(ch)!=10) && (int(ch)!=13) && (int(ch)!=32)){ // To make sure that <LF>, <CR> or Space character is not sent to the WiFi.
      wifiSerial.write(ch);}
  }
  wifiSerial.write(13);         // Send Carriage Return <CR>.
  delay(5);
  CTS_start();
}

void dwifiTCP::writeesc(char start, String data, char finish)
{
  CTS_stop();
  wifiSerial.write(27);  // ESC
  wifiSerial.write(start);  // Start character
   for(int i=0; i<data.length(); i++){  // data
    wifiSerial.write(data.charAt(i));}
  wifiSerial.write(27);  // ESC
  wifiSerial.write(finish);   // Stop character
  CTS_start();
}

/* Function used to receive serial data from WiFi shield. */
void dwifiTCP::Receive(boolean wait=false)
{
  /* Must be preceded by a delay statement:
     Example Preceding code:
       delay(10);
     Example Calls to function:
       int bytesReceived = Receive(true);
       int bytesReceived = Receive(); */
  int torec=0;
  int i=0;
  torec=wifiSerial.available();   // Number of bytes ready to be received.
  // Wait till there is data available to receive.
  if (wait==true){
    while(torec==0){
      delay(5);
      torec=wifiSerial.available();}
  }
  
  int bytewifi2=-1;
  // Receive incoming data.
  while(RTS_check()){
    Serial.print("");
    if(wifiSerial.available()>0){    // If more data available and ready to be received.
      Serial.print("");
      bytewifi=wifiSerial.read();    // Read a byte as an integer.
      buffer[i]=char(bytewifi);      // Convert integer to character.
      // If OK (check K<CR><LF>) is received
      if(buffer[i]=='K'){
        bytewifi2=wifiSerial.read();        // Read character.
        if(bytewifi2==13){
          buffer[++i]=char(bytewifi2);      // If <CR> Put in buffer.
          bytewifi2= wifiSerial.read();     // Read character.
          if(bytewifi2==10){
            buffer[++i]=char(bytewifi2);    // If <LF> Put in buffer and stop reading further characters.
            break;
          }
          else {buffer[++i]=char(bytewifi2);}  // If not <LF> put in buffer.
        }
        else {buffer[++i]=char(bytewifi2);}  // If not <CR> put in buffer.
      }
      // If ERROR (check E-R-R) is received
      if(buffer[i]=='E'){
        buffer[++i]=char(wifiSerial.read()); // Read and put character in buffer.
        bytewifi2=wifiSerial.read();         // Read character.
        if (char(bytewifi2)=='R'){           
          buffer[++i]=char(bytewifi2);       // If 'R' Put in buffer.
          buffer[++i]=char(wifiSerial.read()); // Read and put character in buffer.
          bytewifi2=char(wifiSerial.read());  // Read character.
          if (char(bytewifi2)='R'){           
            buffer[++i]=char(bytewifi2);      // If 'R' Put in buffer and stop reading further characters.
//            Serial.println("Error Encountered");
            break;
          }
          else {buffer[++i]=char(bytewifi2); }   // If not 'R' put in buffer.
        }
        else {buffer[++i]=char(bytewifi2); }  // If not 'R' put in buffer.
      }
      i++;
    }
    CTS_start();
  }

  // Print received data to Serial Monitor Box if wait is true.
  if (wait==true){
     Serial.print(" : ");
     Serial.println(buffer); }
}

void dwifiTCP::readall()
{
  int i=0;
  // Receive incoming data.
  while(RTS_check()){
    Serial.print("");
    if(wifiSerial.available()>0){    // If more data available and ready to be received.
      Serial.print("");
      bytewifi=wifiSerial.read();    // Read a byte as an integer.
      buffer[i]=char(bytewifi);      // Convert integer to character.
      i++;
    }
    CTS_start();
  }
}

/* Function to clear data in buffer. */
void dwifiTCP::clear_read_buffer()
{
  /* Example Call to function: clear_read_buffer(); */
  delay(100);
  memset(buffer, ' ', sizeof(buffer));  // Clear buffer memory.
  CTS_start();
  wifiSerial.write(13);
  delay(10);
  while(wifiSerial.available()>0){  // Probably an error. 
      wifiSerial.read();            // Read to clear out any left over incoming data from WiFi shield.
    }
  delay(100);
}

/* Function to set the baud rate (default = 9600) of the WiFi shield to a value.
   Returns true on successful completion, false otherwise. */
boolean dwifiTCP::set_baud(long baud=9600)
{
  /* Example Call to function: boolean check = set_baud(19200); */
  delay(100);
  clear_read_buffer();
  CTS_stop();
  Serial.print("\nSet baud : ");
  commandStr = "ATB=";
  commandStr += baud;
//  commandStr += ",8,n,2";
  writeStr(commandStr); // Send command ATB=<baud>[,8,n,2] (8 bits per character, no parity, 2 stop bits)
  delay(10);
  Receive(true);
  delay(100);
  wifiSerial.end();                 // End any previously open connections to WiFi.
  wifiSerial.begin(baud);   // Begin new connection to WiFi with selected baudrate value.
  // Example output returned-> <CR><LF>OK
  flag=false;
  if (buffer[2]=='O' && buffer[3]=='K'){
    flag=true;
  }
  return flag;
}

/* Function to find position of a character in character array.
   If character not found, returns value -1. */
int dwifiTCP::inString(char *buf, char ch)
{
  /* Example Call to function: int position = inString("data",'a'); */
  int pos=-1;
  for(int i=0; i<strlen(buf); i++){
    if(ch==buf[i]){
      pos=i;
      break;
    }
  }
  return pos;    
}

/* Function to turn Verbose ON or OFF.
   onoff= true  - Verbose ON. Characters will be received from WiFi. (default)
          false - Verbose OFF. Data received from WiFi will be integer values. 
   Returns true on successful completion, false otherwise. */
boolean dwifiTCP::verbose_on(boolean onoff=true)
{
  /* Example Call to function to enable Verbose: boolean check = verbose_on(true); */
  delay(100);
  clear_read_buffer();
  // Turn Verbose ON
  if (onoff==true){
    Serial.print("\nVerbose ON : "); }
  // Turn Verbose OFF
  if (onoff==false){
    Serial.print("\nVerbose OFF : "); }
  commandStr = "ATV";
  commandStr += onoff;
  writeStr(commandStr);    // Send command "ATV<onoff>" to WiFi. true=1, false=0
  delay(10);
  Receive(true);
  commandStr="";
  // Example output returned-> <CR><LF>OK
  flag=false;
  if (buffer[2]=='O' && buffer[3]=='K'){  
    flag=true;
  }
  return flag;
}

/* Function to turn Echo OFF(0) or ON (1). 
   onoff= false - Echo OFF. WiFi will NOT echo back the commands that are sent to it. (default)
          true  - Echo ON. WiFi will echo back the commands that are sent to it.
   Returns true on successful completion, false otherwise. */
boolean dwifiTCP::echo_on(boolean onoff=false)
{
  /* Example Call to function to disable Echo: boolean check = echo_on(false); */
  delay(100);
  clear_read_buffer();
  // Turn Echo ON
  if (onoff==true){
    Serial.print("\nEcho ON : "); }
  // Turn Echo OFF
  if (onoff==false){
    Serial.print("\nEcho OFF : "); }
  commandStr = "ATE";
  commandStr += onoff;
  writeStr(commandStr);    // Send command "ATE<onoff>" to WiFi. true=1, false=0.
  delay(10);
  Receive(true);
  commandStr="";
   // Example output returned-> <CR><LF>OK
  flag=false;
  if (buffer[2]=='O' && buffer[3]=='K'){
    flag=true;
  }
  return flag;
}

/* Function to scan for baud rate value.
   Returns value of working baud rate OR zero if no value found. */
long dwifiTCP::scan_baud()
{
  /*Example Call to function: long baudRate = scan_baud(); */
  Serial.println("\nScan Baud");
  verbose_on(true);
  delay(500);
  int baudratesize=(sizeof(baudrates)/sizeof(long));  // Number of baudrates in array.
  // Test for correct baud rate from values in 'baudrates' array.
  for (int i=0; i<baudratesize; i++){
    Serial.print("Testing: ");        // Print value of baud rate being
    Serial.println(baudrates[i]);     // tested to Serial Monitor Box.
    wifiSerial.end();                 // End any previously open connections to WiFi.
    wifiSerial.begin(baudrates[i]);   // Begin new connection to WiFi with selected baudrate value.
    clear_read_buffer();
    delay(100);
    commandStr="+++";
    writeStr(commandStr);    // Send command +++
    delay(10);
    Receive(true);
    delay(500);
    // Check if data received contains an OK(O) or ERROR(R).
    if(inString(buffer,'O')>-1 || inString(buffer,'R')>-1){
      clear_read_buffer();
      return baudrates[i];            // Return value of selected baud rate.
    }
  }
  clear_read_buffer();
  return 0;
}

/* Function to convert hexadecimal value in char to integer value.
   For all other values not in [0,9] or [A,F], the function returns 0. */
int dwifiTCP::hex2int(char hex)
{
  /* Example call to function: int value = hex2int('A'); */
  int x;
  if (hex=='0') x=0;
  if (hex=='1') x=1;
  if (hex=='2') x=2;
  if (hex=='3') x=3;
  if (hex=='4') x=4;
  if (hex=='5') x=5;
  if (hex=='6') x=6;
  if (hex=='7') x=7;
  if (hex=='8') x=8;
  if (hex=='9') x=9;
  if (hex=='A') x=10;
  if (hex=='B') x=11;
  if (hex=='C') x=12;
  if (hex=='D') x=13;
  if (hex=='E') x=14;
  if (hex=='F') x=15;
  return x;
}

/* Function to enable or disable Software flow control.
   onoff= true  - Enable Software Flow Control.
          false - Disable Software Flow Control.
   Returns true on successful completion, false otherwise. */
boolean dwifiTCP::soft_flow_control(boolean onoff)
{
  /* Example Call to function: boolean check = soft_flow_control(true); */
  delay(100);
  clear_read_buffer();  
  // Turn Software Flow Control ON
  if (onoff==true){
    Serial.print("\nSoftware Flow Control ON : ");
  }
  // Turn Software Flow Control OFF
  if (onoff==false){
    Serial.print("\nSoftware Flow Control OFF : ");
  }
  commandStr="AT&K";
  commandStr += onoff;
  writeStr(commandStr);    // Send command AT&K<onoff>. true=1, false=0.
  delay(10);
  Receive(true);
  commandStr="";
  // Example output returned-> <CR><LF>OK
  flag=false;
  if (buffer[2]=='O' && buffer[3]=='K'){
    flag=true;
  }
  return flag;
}

/* Function to enable Hardware flow control.
   onoff= true  - Enable Hardware Flow Control.
          false - Disable Hardware Flow Control.
   Returns true on successful completion, false otherwise. */
boolean dwifiTCP::hard_flow_control(boolean onoff)
{
  /* Example Call to function: boolean check = hard_flow_control(false); */
  delay(100);
  clear_read_buffer();
  // Turn Hardware Flow Control ON
  if (onoff==true){
    Serial.print("\nHardware Flow Control ON : ");
  }
  // Turn Hardware Flow Control OFF
  if (onoff==false){
    Serial.print("\nHardware Flow Control OFF : ");
  }
  commandStr="AT&R";
  commandStr += onoff;
  writeStr(commandStr);    // Send command AT&R<onoff>. true=1, false=0;
  delay(10);
  Receive(true);
  commandStr="";
  // Example output returned-> <CR><LF>OK
  flag=false;
  if (buffer[2]=='O' && buffer[3]=='K'){
    flag=true;
  }
  return flag;
}

/* Function to Set Wireless mode.
   val= false - Infrastructure mode
        true  - Ad hoc mode
   Returns true on successful completion, false otherwise. */
boolean dwifiTCP::infra_mode(boolean val)
{
  /* Example Call to function: boolean check = infra_mode(true); */
  delay(100);
  clear_read_buffer();
  // Turn on Infrastructure mode
  if (val==true){
    Serial.print("\nAdhoc Mode : ");    
  }
  // Turn on Adhoc mode
  if (val==false){
    Serial.print("\nInfrastructure Mode : ");
  }
  commandStr = "AT+WM=";
  commandStr += val;
  writeStr(commandStr);  // Send command AT+WM=<!onoff>. true=0, false=1.
  delay(10);
  Receive(true);
  commandStr="";
  // Example output returned-> <CR><LF>OK
  flag=false;
  if (buffer[2]=='O' && buffer[3]=='K'){
    flag=true;
  }
  return flag;
}

/* Function to set Auto Associate Timeout value.
   timer= 0 to 65535 in 10ms value
   (Eg. 500= 5 secs).
   Returns true on successful completion, false otherwise. */
boolean dwifiTCP::set_network_config(unsigned int aatimer)
{
  /* Example Call to function: boolean check = set_network_config(1000); */ 
  delay(100);
  Serial.print("\nNetwork Configuration : ");
  clear_read_buffer();
  commandStr = "ATS1=";
  commandStr += aatimer;
  writeStr(commandStr); // Send command ATS1=<aatimer>. 
  delay(10);
  Receive(true);
  commandStr="";
  // Example output returned-> <CR><LF>OK  
  flag=false;
  if (buffer[2]=='O' && buffer[3]=='K'){
    flag=true;
  }
  return flag;
}

/* Function to set Keep Alive Timer for 0 to 65535 seconds.
   Returns true on successful completion, false otherwise. */
boolean dwifiTCP::keep_alive(unsigned int katimer)
{
  /* Example Call to function: boolean check = keep_alive(1200); */
  delay(100);
  Serial.print("\nKeep Alive : ");
  clear_read_buffer();
  
  commandStr = "AT+PSPOLLINTRL=";
  commandStr += katimer;
  writeStr(commandStr); // Send command AT+PSPOLLINTRL=<katimer>.
  delay(10);
  Receive(true);
  commandStr="";
  
  // Example output returned-> <CR><LF>OK
  flag=false;
  if (buffer[2]=='O' && buffer[3]=='K'){
    flag=true;
  }
  return flag;
}

/* Function to set transmit power value from 0 to 7.
   Returns true on successful completion, false otherwise. */
boolean dwifiTCP::set_transmit_power(int pow)
{
  /* Example Call to function: boolean check = set_transmit_power(7); */
  delay(100);
  pow = constrain(pow, 0, 7);  // Limits value of variable between 0 and 7.
  Serial.print("\nSet Transmit Power : ");
  clear_read_buffer();
  commandStr = "AT+WP=";
  commandStr += pow;
  writeStr(commandStr);  // Send command AT+WP=<pow>.
  delay(10);
  Receive(true);
  commandStr="";
  // Example output returned-> <CR><LF>OK
  flag=false;
  if (buffer[2]=='O' && buffer[3]=='K'){
    flag=true;
  }
  return flag;
}

/* Function to disassociate from network. */
void dwifiTCP::disassociate()
{
  /* Example Call to function: disassociate(); */
  delay(100);
  clear_read_buffer();  
  Serial.print("\nDisassociate : ");
  commandStr = "AT+WD";
  writeStr(commandStr);  // Send command AT+WD.
  delay(10);
  Receive(true);
  commandStr="";
}

/* Function to set the authentication mode for WiFi. 
   mode= 0 - WPA
         1 - Open
         2 - WEP
   Returns true on successful completion, false otherwise. */
boolean dwifiTCP::wifi_auth_mode(int mode)
{
  /* Example Call to function: boolean check = wifi_auth_mode(1); */
  delay(100);
  Serial.print("\nAuthentication Mode : ");
  clear_read_buffer();
  delay(100);
  commandStr = "AT+WAUTH=";
  commandStr += mode;
  writeStr(commandStr);  // Send command AT+WAUTH=<mode>
  delay(10);
  Receive(true);
  commandStr="";
  // Example output returned-> <CR><LF>OK
  flag=false;
  if (buffer[2]=='O' && buffer[3]=='K'){
    flag=true;
  }
  return flag;
}

/* Retrieve information about current network. */
void dwifiTCP::network_stat()
{
  delay(100);
  Serial.print("\nNetwork Status : ");
  clear_read_buffer();
  commandStr="AT+NSTAT=?";
  writeStr(commandStr);
  delay(10);
  Receive(true);
  delay(100);
  commandStr="";
}

/* Function to enable or disable DHCP.
   onoff = true  - DHCP enabled.
         = false - DHCP disabled.
   Returns true on successful completion, false otherwise. */
boolean dwifiTCP::DHCP_enable(boolean onoff)
{
  /* Example Call to function: boolean check = DHCP_enable(true); */
  delay(100);
  // Turn DHCP ON
  if (onoff==true){
    Serial.print("\nDHCP ON : ");
  }
  // Turn DHCP OFF
  if (onoff==false){
    Serial.print("\nDHCP OFF : ");
  }
  clear_read_buffer();  
  commandStr = "AT+NDHCP=";
  commandStr += onoff;
  writeStr(commandStr); // Send command AT+NDHCP=<onoff>. true=1, false=0.
  delay(10);
  Receive(true);
  commandStr="";
  // Example output returned-> <CR><LF>OK
  flag=false;
  if (buffer[2]=='O' && buffer[3]=='K'){
    flag=true;
  }
  return flag;
}

/* Associate with network.
   val = false - Try association only once.
       = true  - Try association till connection established. */
void dwifiTCP::associate_with_network(boolean val)
{
  /* Example Call to function: associate_with_network(true); */
  delay(100);
  Serial.print("\nAssociate with Network : ");
  // Loop to try association atleast once.
  do{
    clear_read_buffer();
    commandStr = "AT+WA=";  // Send command AT+WA=<ssid>
    commandStr += ssid;
    writeStr(commandStr);
    delay(10);
    Receive(true);
    // If OK received. Check 'K' if verbose mode ON check zero if verbose mode OFF
    if ((inString(buffer,'K')>-1)||(inString(buffer,'0')>-1)){
      val=false;}
    commandStr="";
    delay(100);
  }while (val==true);
}

/* Function to setup WEP network. */
void dwifiTCP::setWep()
{
  /* Example Call to function: setWep(); */
  delay(100);
  Serial.print("\nSetup WEP Network : ");
  echo_on(false);
  soft_flow_control(true);
  hard_flow_control(true);
  verbose_on(true);
  infra_mode(false);
  disassociate();
  set_network_config(1000);
  keep_alive(1200);
  set_transmit_power(7);
  wifi_auth_mode(2);
  DHCP_enable(true);
  clear_read_buffer();
  delay(100);
  Serial.print("\nSet WEP Key : ");
  // Set Wep key
  commandStr = "AT+WWEP";
  commandStr += ind;
  commandStr += "=";
  commandStr += key;
  writeStr(commandStr); // Send command AT+WWEP<ind>=<key>
  delay(10);
  Receive(true);
  commandStr="";
}

/* Function to setup WPA network. */
void dwifiTCP::setWpa()
{
  /* Example Call to function: setWpa(); */
  delay(100);
  Serial.print("\nSetup WPA Network : ");
  echo_on(false);
  soft_flow_control(true);
  hard_flow_control(true);
  verbose_on(true);
  infra_mode(false);
  disassociate();
  set_network_config(1000);
  keep_alive(1200);
  set_transmit_power(7);
  wifi_auth_mode(0);
  DHCP_enable(true);
  clear_read_buffer();
  delay(100);    
  Serial.print("\nSet WPA Passphrase : ");
  // Set WPA SSID and Passphrase
  commandStr = "AT+WPAPSK=";
  commandStr += ssid;
  commandStr += ",";
  commandStr += key;
  writeStr(commandStr);  // Send command AT+WPAPSK=<ssid>,<key>
  delay(10);
  Receive(true);
  commandStr="";
}

/* Function to Look-up IP address of a hostname. 
   Returns IP Address of domain as a String. */
String dwifiTCP::dns_lookup(String URL)
{
  /* Example Call to function: String DomainIP = dns_lookup("www.dexterindustries.com"); */
  delay(100);
  Serial.print("\nDNS Lookup : ");
  clear_read_buffer();
  commandStr = "AT+DNSLOOKUP=";
  commandStr += URL;
  writeStr(commandStr);    // Send command AT+DNSLOOKUP=<URL>.
  delay(10);
  Receive(true);
  commandStr="";
  
  // Example output returned-> IP:123.123.12.123<CR><LF>OK<CR><LF>
  output="";
  int buflen=strlen(buffer);
  int j;
  for (int i=0;i<buflen;i++){  //Check buffer.
    j=i+3;
    if (buffer[i]=='I' && buffer[i+1]=='P' && buffer[i+2]==':'){    // Find "IP:" in buffer.
      while (buffer[j]!=13 || buffer[j]!=32){  // Store IP address values till Space or <CR> is encountered.
          output += buffer[j];
          j++;
      }
    }
  }
  output.trim();
  return output;
}

/* Start TCP
   port- port number value from 1 to 65535.
   Returns CID of the Server as an integer between String. */
int dwifiTCP::server_start(unsigned int port)
{
  /* Example call to function: int CID_TCPServer = server_start(2000); */
  delay(100);
  char CID;
  disassociate();      // Dissociate from any previous network.
  DHCP_enable(true);   // Enable DHCP.
  associate_with_network(true);  // Associate with current network.
  clear_read_buffer();
  Serial.print("\nStart a TCP Server : ");
  commandStr = "AT+NSTCP=";  // Send command AT+NSTCP=<port>
  commandStr += port;
  writeStr(commandStr);
  delay(10);
  Receive(true);
  commandStr="";
  // Example output returned-> CONNECT<Space><CID>...OK<CR>
  int buflen=strlen(buffer);
  int j;
  for (int i=0;i<buflen;i++){  //Check buffer.
    j=i+2;
    if (inString(buffer,'T')==i){  // Find "CONNECT" in buffer.
      if (buffer[j]!=13 || buffer[j]!=32){  // Store hexadecimal CID value till Space or <CR> is encountered.
        CID = buffer[j];
        break;
      }
    }
  }
  return hex2int(CID);
}

/* Connect TCP(UDP) Client to a TCP(UDP) Server.
   serverip - IP of Server.
   port - port number used (1 to 65535).
   Returns CID of Client as an integer. */
int dwifiTCP::client_connect(String serverip, unsigned int port)
{
  /* Example call to function: int CID_TCPClient = client_connect("192.168.1.2",2000); */
  delay(100);
  char CID;
  disassociate();     // Disconnect from any previous network.
  DHCP_enable(true);  // Enable DHCP.
  associate_with_network(true);  // Connect to current network.
  clear_read_buffer();
  Serial.print("\nConnect a TCP Client : ");
  commandStr = "AT+NCTCP=";  // Send command AT+NCTCP=<serverip>,<port>.
  commandStr += serverip;
  commandStr += ",";
  commandStr += port;
  writeStr(commandStr); // Send command AT+NCTCP=<serverip>,<port>.
  delay(10);
  Receive(true);
  commandStr="";
  // Example output returned-> CONNECT<Space><CID>...OK<CR>
  int buflen=strlen(buffer);
  int j;
  for (int i=0;i<buflen;i++){  //Check buffer.
    j=i+2;
    if (inString(buffer,'T')==i){  // Find "CONNECT" in buffer.
      if (buffer[j]!=13 || buffer[j]!=32){  // Store hexadecimal CID unless Space or <CR> is encountered.
        CID = buffer[j];
        break;
      }
    }
  }
  return hex2int(CID);
}

/* Send data to TCP Server, TCP Client or UDP Client. 
   Connection type- TCP Server or TCP Client.
   data- data to send.
   CID- Connection Identifier of current connection (0 to 15).
   Module receive sequence: <Esc>S<CID><data><Esc>E  */
void dwifiTCP::tcp_write(String data, int CID)
{
  /* Example call to function: tcp_write("Hello",2); */  
  delay(100);
  commandStr = String(CID,HEX);
  commandStr.toUpperCase();
  commandStr.trim();  // <CID>
  commandStr += data; // <CID><data>
  writeesc('S',commandStr,'E');
}

/* Receive data from TCP Server, TCP Client or UDP Client. 
   Connection type- TCP Server or TCP Client.
   CID- Connection identifier from which to read.
   Module send sequence: <Esc>S<CID><data><Esc>E  */
String dwifiTCP::tcp_read(int CID)
{
  /* Example call to function: String tcpData = tcp_read(2); */  
  readall();
  output="";
  commandStr = String(CID,HEX);
  commandStr.trim();
  commandStr.toUpperCase();
  int buflen=strlen(buffer);
  int j;
  for (int i=0;i<buflen;i++){  //Check buffer.
    j=i+3;
    if (buffer[i]==27 && buffer[i+1]=='S' && String(buffer[i+2])==commandStr){    // Find <ESC>S<CID> in buffer.
      while (buffer[j]!=27 && buffer[j+1]!=69){  // Store data till <ESC>E is encountered.
        output += buffer[j];
        j++;
      }
      break;
    }
  }
  output.trim();
  Serial.print(" Data Received: ");
  Serial.println(output);
  return output;
}


/* Disconnect TCP or UDP Server or Client.
   CID- connection identifier of Server or Client to disconnect (0 to 15). 
   Returns true on successful completion, false otherwise. */
boolean dwifiTCP::cid_disconnect(int CID)
{
  /* Example Preceding Code: 
        int CID_Server = server_start(2000);
  Example call to function: boolean check = cid_disconnect(CID_Server); */
  delay(100);
  Serial.print("\nDisconnect CID: ");
  clear_read_buffer();
  commandStr = "AT+NCLOSE=";
  commandStr += String(CID,HEX);
  commandStr.toUpperCase();
  writeStr(commandStr); // Send command AT+NCLOSE=<CID>.
  delay(10);
  Receive(true);
  commandStr="";
  flag=false;
  if (buffer[2]=='O' && buffer[3]=='K'){
    flag=true;
  }
  return flag;
}

/* Get TCP/UDP Server or Client connection details.
   CID- connection identifier of Server or Client to disconnect (0 to 15). 
   Returns CID number, CID type, Protocol, Local port, Remote port, Remote IP address as a String */
void dwifiTCP::cid_check()
{
  /* Example call to function: String details = cid_check(2); */
  delay(100);
  Serial.print("\nChecking CID : ");
  clear_read_buffer();
  commandStr = "AT+CID=?";
  writeStr(commandStr); // Send command AT+CID=?
  delay(10);
  Receive(true);
  commandStr="";
}
